﻿using Castle.Core.Configuration;
using Castle.Core.Logging;
using Inovout.Application;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Inovout.YunYao.Cattle.WindowsService
{
    /// <summary>
    /// 测点数据持久化服务
    /// 1、读取Redis队列、HBase数据库、运行环境配置和监控配置信息
    /// 2、根据运行环境配置创建N个工作线程，每个工作线程处理1个队列
    /// 3、创建监控线程，到达不同阀值做出发送邮件或加开一个线程处理队列数据。
    /// 4、订阅线程异常事件，根据线程类型决定重启线程。
    /// </summary>
    public class NodePersistentService
    {
        private ILogger logger;
        private IApplication application;
        public NodePersistentService(IApplication application)
        {
            this.application = application;
            logger = ComponentRegistry.Resolve<ILogger>();
            persistentTasks = new List<PersistentTask>();
            initialize();
        }
        private List<PersistentTask> persistentTasks;
        private IConfiguration redisQueuesConfiguration;
        private IConfiguration hbaseConfiguration;
        private IConfiguration persistentConfiguration;
        private IConfiguration monitorConfiguration;
        private void initialize()
        {
            redisQueuesConfiguration = application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("redisQueues"));
            hbaseConfiguration = application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("hbase"));
            persistentConfiguration = application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("persistent"));
            monitorConfiguration = application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("monitor"));
            foreach (var redisQueueConfiguration in redisQueuesConfiguration.Children)
            {
                string[] queueNames = redisQueueConfiguration.Attributes["names"].Split(',');
                foreach (string queueName in queueNames)
                {
                    persistentTasks.Add(new PersistentTask {
                        RedisIP = redisQueueConfiguration.Attributes["ip"].Trim(),
                        RedisPort = int.Parse(redisQueueConfiguration.Attributes["port"].Trim()),
                        RedisTableId=int.Parse(redisQueueConfiguration.Attributes["tableId"].Trim()),
                        QueueName=queueName.Trim(),
                        HBaseIP=hbaseConfiguration.Attributes["ip"].Trim(),
                        HBasePort=int.Parse(hbaseConfiguration.Attributes["port"].Trim()),
                        HBaseTableNamePrefix = hbaseConfiguration.Attributes["tableNamePrefix"].Trim(),
                        BatchCount=int.Parse(persistentConfiguration.Attributes["BatchCount"].Trim())
                    });
                }
            }
            monitorTask=new MonitorTask{
                 PersistentTasks=persistentTasks,
                 Interval=int.Parse(monitorConfiguration.Attributes["interval"].Trim()),
                 HelperQueueName=monitorConfiguration.Attributes["helperQueueName"].Trim(),
                 MaxQueueCount =long.Parse(monitorConfiguration.Attributes["maxQueueCount"].Trim()),
                 BatchCount=int.Parse(monitorConfiguration.Attributes["batchCount"].Trim())
            };
            AppDomain.CurrentDomain.UnhandledException+=AppDomain_UnhandledException;
        }

        void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Thread exceptionThread = e.ExceptionObject as Thread;
            if (exceptionThread != null)
            {
                PersistentTask persistentTask = persistentTasks.SingleOrDefault(
                        task=>task.DataCattle.Thread.Equals(exceptionThread));
                if (persistentTask != null)
                {
                    StartPersistentTaskThread(persistentTask);
                }
                if (monitorTask.Thread.Equals(exceptionThread))
                {
                    StartMonitorTaskThread(monitorTask);
                }
            }
            logger.Error("未知异常，线程出错！");
            AlertManager.Send(this.GetType().Name);

        }
        private MonitorTask monitorTask;
        private void StartPersistentTaskThread(PersistentTask task)
        {
            DataCattle dataCattle = new DataCattle(task);
            dataCattle.Do();
            //ThreadStart threadStart = new ThreadStart(dataCattle.Do);
            //Thread thread = new Thread(threadStart);
            //dataCattle.Thread = thread;
            //thread.Start();
        }
        private void StartMonitorTaskThread(MonitorTask task)
        {

            DataDrover dataDrover = new DataDrover(task);
            ThreadStart threadStart = new ThreadStart(dataDrover.Do);
            Thread thread = new Thread(threadStart);
            dataDrover.Thread = thread;
            thread.Start();
        }
        public void Stop()
        {
            //等待当前队列处理完成后，便不再处理。
        }
        public void Start()
        {
            foreach (var task in persistentTasks)
            {
                StartPersistentTaskThread(task);
            }
            StartMonitorTaskThread(monitorTask);
        }
    }
}
